﻿using FileToVideo.AddFunc;
using FileToVideo.Helpers;
using FileToVideo.Enums;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;
using System.Text.RegularExpressions;
using System.IO;
using FileToVideo.Config;
using FileToVideo.Class;
using System.Text.Json;
using System.Threading.Tasks;

namespace FileToVideo
{
    public partial class MainWindow : Window
    {
        /// <summary>
        /// 日志记录器
        /// </summary>
        private static Logger logger = new ();

        /// <summary>
        /// 读取密码的正则表达式
        /// </summary>
        private static Regex readPassword = new(@"^[a-zA-Z0-9!@#$%^&*()_+\-=\[\]{};':""\\|,.<>\/?]{4,20}$");

        /// <summary>
        /// 功能索引
        /// </summary>
        private int functionIndex = 0;

        /// <summary>
        /// 功能颜色
        /// </summary>
        public string functionColor = "#FFFFFF";

        /// <summary>
        /// 默认颜色
        /// </summary>
        public string functionDefaultColor = "#00A0E9";

        /// <summary>
        /// 功能按钮
        /// </summary>
        public List<Button> functionButtons = new List<Button>();

        /// <summary>
        /// 加密的视频文件路径
        /// </summary>
        public string videoFilePath = "";

        /// <summary>
        /// 要加密的文件路径
        /// </summary>
        public string encodingfilePath = "";

        /// <summary>
        /// 是否在播放媒体
        /// </summary>
        private bool isMediaPlaying = false;

        /// <summary>
        /// 是否全屏
        /// </summary>
        private bool isFullScreen = false;

        /// <summary>
        /// 全屏窗口
        /// </summary>
        private Window? _fullscreenWindow;

        /// <summary>
        /// 视频组件父类
        /// </summary>
        private Grid _parent;

        /// <summary>
        /// 视频组件原有边距
        /// </summary>
        private Thickness _originalMargin;

        /// <summary>
        /// 视频组件原有宽度
        /// </summary>
        private double _originalWidth;

        /// <summary>
        /// 视频组件原有高度
        /// </summary>
        private double _originalHeight;

        /// <summary>
        /// 是否正在拖动媒体
        /// </summary>
        private bool isMediaDragging = false;

        /// <summary>
        /// 定时器
        /// </summary>
        private DispatcherTimer timer;

        /// <summary>
        /// 密码
        /// </summary>
        public string password = "";

        /// <summary>
        /// 是否输出到输入目录
        /// </summary>
        public bool outputToInputDir = true;

        /// <summary>
        /// 是否在拖拽分块大小
        /// </summary>
        public bool isPartSizeDragging = false;

        /// <summary>
        /// 是否在拖拽帧重复量
        /// </summary>
        public bool isFpsDragging = false;

        /// <summary>
        /// 分块大小
        /// </summary>
        public PartSizeMode_1080P partSizeMode = PartSizeMode_1080P.SIZE_1;

        /// <summary>
        /// 帧重复量
        /// </summary>
        public int frameRepetition = Setting.frameRepetition;

        /// <summary>
        /// 每秒帧数
        /// </summary>
        public int FPS = Setting.FPS;

        /// <summary>
        /// 功能索引
        /// </summary>
        public int FunctionIndex
        {
            get
            {
                return functionIndex;
            }
            set
            {
                // 清空数据
                filePathText.Text = null;
                MediaPlayer.Source = null;

                // 修改按钮样式
                functionButtons.ForEach(button =>
                {
                    button.Background = new SolidColorBrush((Color)ColorConverter.ConvertFromString(functionDefaultColor));
                });
                switch (value)
                {
                    case 0:
                        File2Video.Background = new SolidColorBrush((Color)ColorConverter.ConvertFromString(functionColor));
                        filePathText_Tooltip.Text = String.IsNullOrEmpty(encodingfilePath) ? "请选择需要加密的文件地址" : "文件地址:\n" + encodingfilePath;
                        filePathText.Text = encodingfilePath;
                        break;
                    case 1:
                        Video2File.Background = new SolidColorBrush((Color)ColorConverter.ConvertFromString(functionColor));
                        filePathText_Tooltip.Text = String.IsNullOrEmpty(videoFilePath) ? "请选择视频文件地址" : "视频地址:\n" + videoFilePath;
                        filePathText.Text = videoFilePath;
                        break;
                    default:
                        return;
                }
                functionIndex = value;
            }
        }

        public MainWindow()
        {
            InitializeComponent();

            // 初始化功能按钮
            functionButtons.Add(File2Video);
            functionButtons.Add(Video2File);

            // 设置初始功能
            FunctionIndex = 0;

            // 初始化定时器
            InitializeTimer();

            // 初始化选择器
            CodingModeBox.ItemsSource = (CodingMode[])Enum.GetValues(typeof(CodingMode));
            CodingModeBox.SelectedValue = CodingMode.NONE;

            // 初始化编码方式
            EncryptModeBox.ItemsSource = (EncryptMode[])Enum.GetValues(typeof(EncryptMode));
            EncryptModeBox.SelectedValue = EncryptMode.NONE;

            // 初始化分块大小
            PartSizeText.Content = ((int)partSizeMode).ToString();
            FrameDataSize.Content = $"{partSizeMode.FrameSize()} B";

            // 初始化帧重复量
            FPSText.Content = frameRepetition.ToString();

        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Close();
        }

        private void MinimizeButton_Click(object sender, RoutedEventArgs e)
        {
            WindowState = WindowState.Minimized;
        }

        private void moveThumb_DragDelta(object sender, System.Windows.Controls.Primitives.DragDeltaEventArgs e)
        {
            Left += e.HorizontalChange;
            Top += e.VerticalChange;
        }

        private void Author_MouseUp(object sender, MouseButtonEventArgs e)
        {
            Item.OpenOnWindows("https://gitee.com/huimengli/fileToVideo");
        }

        private void File2Video_Click(object sender, RoutedEventArgs e)
        {
            FunctionIndex = 0;
        }

        private void Video2File_Click(object sender, RoutedEventArgs e)
        {
            FunctionIndex = 1;
        }

        private void visit_Click(object sender, RoutedEventArgs e)
        {
            switch (FunctionIndex)
            {
                case 0:
                    Item.ChoiceFile(ref encodingfilePath, "选择要加密文件", Environment.SpecialFolder.MyDocuments, "*.*");
                    logger.Log(encodingfilePath);
                    filePathText.Text = encodingfilePath;
                    filePathText_Tooltip.Text = String.IsNullOrEmpty(encodingfilePath) ? "请选择需要加密的文件地址" : "文件地址:\n" + encodingfilePath;
                    break;
                case 1:
                    Item.ChoiceFile(ref videoFilePath, "选择加密的视频", Environment.SpecialFolder.MyDocuments, "*.mp4");
                    logger.Log(videoFilePath);
                    filePathText.Text = videoFilePath;
                    filePathText_Tooltip.Text = String.IsNullOrEmpty(videoFilePath) ? "请选择视频文件地址" : "视频地址:\n" + videoFilePath;
                    LoadVideo();
                    break;
                default:
                    break;
            }            
        }

        private void filePathText_FocusableChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            switch (FunctionIndex)
            {
                case 0:
                    encodingfilePath = filePathText.Text;
                    filePathText_Tooltip.Text = String.IsNullOrEmpty(encodingfilePath) ? "请选择需要加密的文件地址" : "文件地址:\n" + encodingfilePath;
                    break;
                case 1:
                    videoFilePath = filePathText.Text;
                    filePathText_Tooltip.Text = String.IsNullOrEmpty(videoFilePath) ? "请选择视频文件地址" : "视频地址:\n" + videoFilePath;
                    break;
                default:
                    break;
            }
        }

        #region 媒体播放器相关

        /// <summary>
        /// 初始化定时器
        /// </summary>
        private void InitializeTimer()
        {
            timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromMilliseconds(500);
            timer.Tick += Timer_Tick;
        }
        
        /// <summary>
        /// 加载视频
        /// </summary>
        private void LoadVideo()
        {
            // 这里可以改为打开文件对话框选择视频
            // OpenFileDialog openFileDialog = new OpenFileDialog();
            // if (openFileDialog.ShowDialog() == true)
            // {
            //     MediaPlayer.Source = new Uri(openFileDialog.FileName);
            // }

            // 示例：加载一个示例视频（需要替换为实际路径）
            try
            {
                MediaPlayer.Source = new Uri(videoFilePath);
            }
            catch
            {
                MessageBox.Show("请加载有效的视频文件");
            }
        }

        private void MediaPlayer_MediaOpened(object sender, RoutedEventArgs e)
        {
            ProgressSlider.Maximum = MediaPlayer.NaturalDuration.TimeSpan.TotalSeconds;
            VolumeSlider.Value = MediaPlayer.Volume;
            timer.Start();
            UpdateTimeDisplay();
        }

        private void MediaPlayer_MediaEnded(object sender, RoutedEventArgs e)
        {
            isMediaPlaying = false;
            MediaPlayer.Stop();
            UpdatePlayPauseIcon();
        }

        private void Timer_Tick(object sender, EventArgs e)
        {
            if (!isMediaDragging && MediaPlayer.NaturalDuration.HasTimeSpan)
            {
                ProgressSlider.Value = MediaPlayer.Position.TotalSeconds;
                UpdateTimeDisplay();
            }
        }

        private void UpdateTimeDisplay()
        {
            if (MediaPlayer.NaturalDuration.HasTimeSpan)
            {
                TimeTextBlock.Text = $"{MediaPlayer.Position:mm\\:ss} / {MediaPlayer.NaturalDuration.TimeSpan:mm\\:ss}";
            }
        }

        private void PlayPauseButton_Click(object sender, RoutedEventArgs e)
        {
            if (isMediaPlaying)
            {
                MediaPlayer.Pause();
            }
            else
            {
                MediaPlayer.Play();
            }
            isMediaPlaying = !isMediaPlaying;
            UpdatePlayPauseIcon();
        }

        private void UpdatePlayPauseIcon()
        {
            PlayPauseIcon.Data = isMediaPlaying ?
                (Geometry)FindResource("PauseIcon") :
                (Geometry)FindResource("PlayIcon");
        }

        private void ProgressSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            if (!isMediaDragging) return;

            MediaPlayer.Position = TimeSpan.FromSeconds(ProgressSlider.Value);
            UpdateTimeDisplay();
        }

        private void ProgressSlider_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e)
        {
            isMediaDragging = true;
        }

        private void ProgressSlider_DragCompleted(object sender, System.Windows.Controls.Primitives.DragCompletedEventArgs e)
        {
            isMediaDragging = false;
            MediaPlayer.Position = TimeSpan.FromSeconds(ProgressSlider.Value);
        }

        private void VolumeSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            MediaPlayer.Volume = VolumeSlider.Value;
        }

        private void MuteButton_Click(object sender, RoutedEventArgs e)
        {
            MediaPlayer.Volume = MediaPlayer.Volume > 0 ? 0 : 0.5;
            VolumeSlider.Value = MediaPlayer.Volume;
        }

        private void FullScreenButton_Click(object sender, RoutedEventArgs e)
        {
            if(isFullScreen == false)
            {
                // 创建全屏窗口
                _fullscreenWindow = new Window
                {
                    WindowStyle = WindowStyle.None,
                    WindowState = WindowState.Maximized,
                    Topmost = true
                };

                // 将MediaElement移动到新窗口
                _parent = (Grid)MediaPlayer.Parent;
                _originalMargin = MediaPlayer.Margin;
                _originalWidth = MediaPlayer.Width;
                _originalHeight = MediaPlayer.Height;
                _parent.Children.Remove(MediaPlayer);
                _fullscreenWindow.Content = new Grid { Children = { MediaPlayer } };
                MediaPlayer.Margin = new Thickness(0);
                MediaPlayer.Width = _fullscreenWindow.Width;
                MediaPlayer.Height = _fullscreenWindow.Height;

                // 显示全屏窗口
                _fullscreenWindow.Show();

                // 处理ESC键退出全屏
                _fullscreenWindow.PreviewKeyDown += (s, e) =>
                {
                    if (e.Key == Key.Escape) ExitFullscreen(s,e);
                };
            }
        }

        private void ExitFullscreen(Object sender, RoutedEventArgs e)
        {
            if (isFullScreen)
            {
                return;
            }
            else
            {
                isFullScreen = false;

                if (_fullscreenWindow == null)
                {
                    MessageBox.Show("全屏窗口未创建");
                    return;
                }

                // 移动回主窗口
                var grid = (Grid)this.Content;
                ((Grid)_fullscreenWindow.Content)?.Children.Remove(MediaPlayer);
                MediaPlayer.Margin = _originalMargin;
                MediaPlayer.Width = _originalWidth;
                MediaPlayer.Height = _originalHeight;
                _parent.Children.Insert(0,MediaPlayer);

                // 关闭全屏窗口
                _fullscreenWindow.Close();
                _fullscreenWindow = null;
            }
        }

        protected override void OnClosed(EventArgs e)
        {
            MediaPlayer.Close();
            timer?.Stop();
            base.OnClosed(e);
        }

        #endregion

        private void CodingModeBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if ((CodingMode)CodingModeBox.SelectedValue == CodingMode.NONE)
            {
                Password_Grid.IsEnabled = false;
            }
            else
            {
                Password_Grid.IsEnabled = true;
            }
        }

        private void EncryptModeBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {

        }

        private void PasswordText_TextChanged(object sender, TextChangedEventArgs e)
        {
            password = PasswordText.Text;
            if (readPassword.IsMatch(password) == false)
            {
                PasswordBorder.BorderBrush = new SolidColorBrush(Colors.Red);
            }
            else
            {
                PasswordBorder.BorderBrush = new SolidColorBrush(Colors.Transparent);
            }
        }

        private void ShowPassword_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show(password);
        }

        private void OutputToSourceFolder_Checked(object sender, RoutedEventArgs e)
        {
            outputToInputDir = true;
        }

        private void OutputToTargetFolder_Checked(object sender, RoutedEventArgs e)
        {
            outputToInputDir = false;
        }

        private void Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            if (isPartSizeDragging == false) return;
            double value = PartSizeSlider.Value;
            int index = (int)Math.Floor(value / 10 * (PartSizeModeAdd.Video1080P().Length() - 1));
            partSizeMode = (PartSizeMode_1080P)PartSizeModeAdd.Video1080P()[index];
            PartSizeText.Content = ((int)partSizeMode).ToString();
            FrameDataSize.Content = partSizeMode.FrameSizeNoError().ToString() + " B";
        }

        private void Slider_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e)
        {
            isPartSizeDragging = true;
        }

        private void Slider_DragEnded(object sender, System.Windows.Controls.Primitives.DragCompletedEventArgs e)
        {
            isPartSizeDragging = false;
        }

        private void FPSSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            if (isFpsDragging == false) return;
            int value = (int)(FPSSlider.Value*9.9)+1;
            frameRepetition = value;
            FPSText.Content = value.ToString();
        }

        private void FPSSlider_DragStarted(object sender, System.Windows.Controls.Primitives.DragStartedEventArgs e)
        {
            isFpsDragging = true;
        }

        private void FPSSlider_DragEnded(object sender, System.Windows.Controls.Primitives.DragCompletedEventArgs e)
        {
            isFpsDragging = false;
        }


        private async void GenerateOrPreview_Click(object sender, RoutedEventArgs e)
        {
            string outputPath = "";
            if (outputToInputDir)
            {
                var inputPath = filePathText.Text;
                FileInfo inputFileInfo = new FileInfo(inputPath);
                outputPath = Path.Combine(
                    inputFileInfo.DirectoryName ?? "", 
                    inputFileInfo.Name.Substring(0,inputFileInfo.Name.Length - inputFileInfo.Extension.Length) + ".mp4"
                );
            }
            else
            {
                Item.ChoiceFolder(ref outputPath, "选择输出文件夹", Environment.SpecialFolder.MyDocuments);
                outputPath = Path.Combine(
                    outputPath,
                    "output.mp4"
                );
            }

            // 创建帧数据工具
            FrameDataUtils frameDataUtils = new FrameDataUtils(
                (EncryptMode)EncryptModeBox.SelectedValue,
                (CodingMode)CodingModeBox.SelectedValue,
                password,
                partSizeMode,
                Setting.width,
                Setting.height,
                outputPath,
                false,
                FPS,
                frameRepetition
            );

            // 开始创建首帧数据
            var frame = new FirstFrame();
            frame.width = Setting.width;
            frame.height = Setting.height;
            frame.frame_repetition = frameRepetition;
            frame.frame_rate = FPS;
            frame.is_rgba = false;
            frame.encryptMode = (EncryptMode)EncryptModeBox.SelectedValue;
            frame.encoding = (CodingMode)CodingModeBox.SelectedValue;
            frame.part_size = partSizeMode;
            frame.frame_id = 0;
            frame.frame_type = FrameTypeMods.First;
            frame.name = new FileInfo(filePathText.Text).Name;
            var data = frame.ToSave();

            try
            {
                Hide();
           
                // 写入数据(调用 loading 的版本) (纯色帧,默认每个色写入30帧)
                await frameDataUtils.WriteStringIntoVideo(Base64.Encode(data));

                // 开始写入数据帧
                await frameDataUtils.OpenFileWrite2Video(filePathText.Text);
            } catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            finally
            {
                // 回收内存
                GC.Collect();
                // 显示主界面
                Show();
            }

            // 销毁帧数据工具
            frameDataUtils.Dispose();

            // 打开视频所在文件夹
            Item.OpenFile(outputPath);
        }

        private async void Export_Click(object sender, RoutedEventArgs e)
        {
            // TODO: 导出功能X 先测试读取视频能否转换回数据
            MessageBox.Show("导出功能正在开发中，敬请期待！");

            string inputPath = filePathText.Text;
            if (File.Exists(inputPath) == false)
            {
                MessageBox.Show("请输入有效的视频文件路径！");
                return;
            }

            // 创建帧数据工具
            FrameDataUtils frameDataUtils = new FrameDataUtils(
                (EncryptMode)EncryptModeBox.SelectedValue,
                (CodingMode)CodingModeBox.SelectedValue,
                password,
                partSizeMode,
                Setting.width,
                Setting.height,
                inputPath,
                true
            );

            // 读取数据
            var data = "";
            try
            {
                // 关闭当前界面
                Hide();

                // 读取数据
                data = await frameDataUtils.ReadStartData();
                Item.logger.Log(data);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            finally
            {
                // 回收内存
                GC.Collect();
                // 打开当前界面
                Show();
            }

            // 尝试解析
            try
            {
                // 关闭界面
                Hide();

                var str = Base64.Decode(data);
                var frame = JsonSerializer.Deserialize<FirstFrame>(str);
                if (frame == null) { throw new Exception("首帧数据为空!"); }

                // 修改UI
                EncryptModeBox.SelectedValue = frame.encryptMode;
                CodingModeBox.SelectedValue = frame.encoding;
                partSizeMode = frame.part_size;
                PartSizeSlider.Value = PartSizeModeAdd.Video1080P().IndexOf((int)partSizeMode) / PartSizeModeAdd.Video1080P().Length() * 10;
                PartSizeText.Content = ((int)partSizeMode).ToString();
                FrameDataSize.Content = partSizeMode.FrameSizeNoError().ToString() + " B";
                frameRepetition = frame.frame_repetition;
                FPSText.Content = frameRepetition.ToString();

                // 修改工具
                frameDataUtils.UpdateSetting(
                    frame.encryptMode,
                    frame.encoding,
                    frame.part_size,
                    frame.name,
                    frame.frame_repetition
                );

                // 开始读取帧数据
                int skipCount = data.Length * Setting.frameRepetition; // 跳过帧
                await frameDataUtils.ReadFrameData(inputPath, skipCount, partSizeMode,frame.name);

                // 打开输出文件所在文件夹
                Item.OpenFile(frame.name);
            } catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            finally
            {
                // 回收内存
                GC.Collect();
                // 显示主界面
                Show();
            }

            // 销毁帧数据工具
            frameDataUtils.Dispose();
        }
    }
}